package cn.tedu.pet.passport.service.impl;

import cn.tedu.pet.passport.ex.ServiceException;
import cn.tedu.pet.passport.mapper.AdminMapper;
import cn.tedu.pet.passport.mapper.AdminRoleMapper;
import cn.tedu.pet.passport.pojo.entity.Admin;
import cn.tedu.pet.passport.pojo.entity.AdminRole;
import cn.tedu.pet.passport.pojo.param.AdminAddNewParam;
import cn.tedu.pet.passport.pojo.param.AdminLoginInfoParam;
import cn.tedu.pet.passport.pojo.param.AdminUpdateInfoParam;
import cn.tedu.pet.passport.pojo.vo.AdminListItemVO;
import cn.tedu.pet.passport.pojo.vo.AdminLoginInfoVO2;
import cn.tedu.pet.passport.pojo.vo.AdminStandardVO;
import cn.tedu.pet.passport.pojo.vo.PageData;
import cn.tedu.pet.passport.security.AdminDetails;
import cn.tedu.pet.passport.service.IAdminService;
import cn.tedu.pet.passport.util.PageInfoToPageDataConverter;
import cn.tedu.pet.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Value("${pet.jwt.secret-key}")
    private String secretKey;
    @Value("${pet.jwt.duration-in-minute}")
    private Long durationInMinute;

    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    public AdminServiceImpl() {
        log.debug("创建业务类对象：AdminServiceImpl");
    }


    @Override
    public AdminLoginInfoVO2 login(AdminLoginInfoParam adminLoginInfoParam) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", adminLoginInfoParam);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoParam.getUsername(),
                adminLoginInfoParam.getPassword());
        Authentication authenticateResult=
                authenticationManager.authenticate(authentication);
        log.debug("验证登录完成！认证结果：{}",authenticateResult);

        Object principal =authenticateResult.getPrincipal();
        log.debug("认证结果中的当事人：{}", authenticateResult.getPrincipal());
        AdminDetails adminDetails= (AdminDetails) principal;
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        Map<String,Object> claims =new HashMap<>();
        claims.put("id",adminDetails.getId());
        claims.put("username",adminDetails.getUsername());
        claims.put("authoritiesJsonString", JSON.toJSONString(authorities));

        long tokenDuration = durationInMinute * 60 * 1000;
        Date tokenExpiration = new Date(System.currentTimeMillis() + tokenDuration);
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(tokenExpiration)
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // 生成
                .compact();
        log.debug("生成了此管理员的信息对应的JWT：{}", jwt);
        AdminLoginInfoVO2 adminLoginInfoVO2 = new AdminLoginInfoVO2()
                .setId(adminDetails.getId())
                .setUsername(adminDetails.getUsername())
                .setAvatar(adminDetails.getAvatar())
                .setToken(jwt)
                .setTokenExpiration(tokenExpiration);
        log.debug("生成了此管理员的信息对应的JWT：{}", adminLoginInfoVO2);
        return adminLoginInfoVO2;


    }

    @Override
    public void logout(String jwt) {
        log.debug("开始处理【管理员退出登录】的请求，参数：{}", jwt);
    }

    @Override
    public void addNew(AdminAddNewParam adminAddNewParam) {
        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewParam);
        // 检查管理员用户名是否被占用，如果被占用，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", adminAddNewParam.getUsername());
        int count = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员用户名统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "添加管理员失败，用户名已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("phone", adminAddNewParam.getPhone());
        count = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员手机号码统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "添加管理员失败，手机号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        QueryWrapper<Admin> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("email", adminAddNewParam.getEmail());
        count = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员邮箱统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "添加管理员失败，邮箱号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        QueryWrapper<Admin> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("bank_card", adminAddNewParam.getBankCard());
        count = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员银行卡统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "添加管理员失败，银行卡已经被使用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Admin admin = new Admin();
        String encodedPassword =passwordEncoder.encode(adminAddNewParam.getPassword());
        adminAddNewParam.setPassword(encodedPassword);
        BeanUtils.copyProperties(adminAddNewParam, admin);
        admin.setLoginCount(0);
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        adminMapper.insert(admin);
        log.debug("将新的管理员数据插入到数据库，完成！");

        // 将管理员与角色的关联数据写入到数据库中
        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRoleList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoleList.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList[i] = adminRole;
        }
       
        adminRoleMapper.insertBatch(adminRoleList);
        log.debug("将新的管理员与角色的关联数据插入到数据库，完成！");
    }

    @Override
    public void deleteById(Long adminId) {
        log.debug("开始处理【根据ID删除管理员】的业务，参数：{}",adminId);
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", adminId);
        int countById =adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if(countById==0){
            String message = "删除管理员失败，管理员ID不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }

        log.debug("开始处理【根据ID删除管理员与角色相关】的业务，参数：{}",adminId);
        QueryWrapper<AdminRole> queryWrapper1 =new QueryWrapper<>();
        queryWrapper1.eq("admin_id",adminId);
        countById=adminRoleMapper.selectCount(queryWrapper1);
        int deleteByID = adminRoleMapper.deleteByAdminId(adminId);
        if(countById!=deleteByID){
            String message = "删除管理员与角色相关失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        log.debug("即将执行删除数据，参数：{}", adminId);
        int rows = adminMapper.deleteById(adminId);
        if (rows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public PageData<AdminListItemVO> list(Integer pageNum) {
        Integer pageSize = 5;
        return list(pageNum, pageSize);
    }

    @Override
    public PageData<AdminListItemVO> list(Integer pageNum, Integer pageSize) {
        log.debug("开始处理【查询管理员列表】的业务，页码：{}，每页记录数：{}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AdminListItemVO> list = adminMapper.list();
        PageInfo<AdminListItemVO> pageInfo = new PageInfo<>(list);
        PageData<AdminListItemVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("查询完成，即将返回：{}", pageData);
        return pageData;
    }

    @Override
    public void updateInfoById(Long adminId, AdminUpdateInfoParam adminUpdateInfoParam) {
        log.debug("开始处理【修改管理员详情】的业务，ID：{}, 新数据：{}", adminId, adminUpdateInfoParam);
        // 检查管理员是否存在，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",adminId );
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "修改管理员详情失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        QueryWrapper<Admin> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("username", adminUpdateInfoParam.getUsername())
                .ne("id",adminId);
        int count = adminMapper.selectCount(queryWrapper2);
        log.debug("根据管理员名称统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "修改管理员详情失败，管理员名称已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        QueryWrapper<Admin> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("phone", adminUpdateInfoParam.getUsername())
                .ne("id",adminId);
         count = adminMapper.selectCount(queryWrapper3);
        log.debug("根据电话号码统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "修改管理员详情失败，电话号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }


        QueryWrapper<Admin> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("email", adminUpdateInfoParam.getUsername())
                .ne("id",adminId);
        count = adminMapper.selectCount(queryWrapper4);
        log.debug("根据邮箱号码统计匹配的管理员数量，结果：{}", count);
        if (count > 0) {
            String message = "修改管理员详情失败，邮箱号码已经被占用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        adminRoleMapper.deleteByAdminId(adminId);
        Admin admin = new Admin();
       // String encodedPassword =passwordEncoder.encode(adminUpdateInfoParam.getPassword());
       // adminUpdateInfoParam.setPassword(encodedPassword);
        BeanUtils.copyProperties(adminUpdateInfoParam, admin);
        admin.setId(adminId);
        int rows = adminMapper.updateById(admin);
        if (rows != 1) {
            String message = "修改管理员详情失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.debug("将新的管理员数据更新入到数据库，完成！");
        Long[] roleIds = adminUpdateInfoParam.getRoleIds();
        AdminRole[] adminRoleList = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoleList.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList[i] = adminRole;
        }
        adminRoleMapper.insertBatch(adminRoleList);
        log.debug("将新的管理员与角色的关联数据插入到数据库，完成！");
    }

    @Override
    public AdminStandardVO getStandardById(Long adminId) {
        log.debug("开始处理【根据ID查询管理员详情】的业务，参数：{}", adminId);
        AdminStandardVO queryResult = adminMapper.getStandardById(adminId);

        log.debug("queryResult ={}",queryResult);
        if (queryResult == null) {
            String message = "查询管理员详情失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return queryResult;
    }

    @Override
    public void updateInfoByUsername(String username, String password) {
        log.debug("开始处理【修改管理员密码】的业务，ID：{}, 新数据：{}", username);
        QueryWrapper<Admin> queryWrapper =new QueryWrapper();
        queryWrapper.eq("username",username );
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员用户名统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "修改管理员密码失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        String encodedPassword =passwordEncoder.encode(password);
        adminMapper.updatePassword(username,encodedPassword);
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }

    private void updateEnableById(Long id, int enable) {
        log.debug("开始处理【{}管理员】的业务，ID：{}，目标状态：{}", ENABLE_TEXT[enable], id, enable);
        // 检查数据是否存在
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = ENABLE_TEXT[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查当前状态是否与参数表示的状态相同
        if (queryResult.getEnable().equals(enable)) {
            String message = ENABLE_TEXT[enable] + "管理员失败，当前管理员已经处于"
                    + ENABLE_TEXT[enable] + "状态！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 准备执行更新
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        log.debug("即将修改数据，参数：{}", admin);
        int rows = adminMapper.updateById(admin);
        if (rows != 1) {
            String message = ENABLE_TEXT[enable] + "管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }


}
